DEFINITION MODULE  Queues;

(*****************************************************************************)
(* Dieses Modul enthaelt Prozeduren zur Erzeugung und Verwaltung einer Queue *)
(* (FIFO - Warteschlange ). Die Queueoperationen sind nicht an einen bestimm-*)
(* ten Datentyp gebunden, d.h. aber auch, dass keine Typueberpruefung - we-  *)
(* der zur Uebersetzungszeit noch zur Laufzeit - vorgenommen wird.           *)
(* Wird jedoch zur Laufzeit ein Parameter mit anderem Speicherbedarf benutzt *)
(* als bei der Queuedefinition angegeben wurde, gibt es einen Fehler         *)
(* ( --> sizeErr ).                                                          *)
(*                                                                           *)
(* Da Warteschlangen wohl hauptsaechlich bei der Prozessverwaltung eingesetzt*)
(* werden und die Prozessbeschreibungsbloecke evtl. in mehreren Warteschlan- *)
(* gen oder anderen Statusbloecken stehen, ist es wichtig, sicherzustellen,  *)
(* dass bei einem bestimmten Prozess immer mit demselben Prozessbeschrei-    *)
(* bungsblock gearbeitet wird und nicht mit irgendeiner Kopie. In diesem Fall*)
(* benutzt man als Parameter nur die Adressen der eigentlichen Elemente,     *)
(* die so auch in unterschiedlichen Warteschlangen stehen koennen aber in    *)
(* Wirklichkeit nur einmal vorhanden sind.                                   *)
(* Wenn also ein Element veraendert wird, so ist diese Aenderung auch in     *)
(* allen anderen Warteschlangen bekannt, in denen dieses Element steht, da   *)
(* nur Verweise auf die Elemente gespeichert werden; das funktioniert so-    *)
(* lange, wie das Element selber an einem festen Platz steht; wird also z.B. *)
(* bei dynamischer Speicheranforderung fuer einen Prozessblock, der Speicher *)
(* nach Prozessende wieder freigegeben, so muessen VORHER die Verweise auf   *)
(* diesen Block in saemtlichen Queues mittels "Remove" entfernt werden, da   *)
(* sonst Referenzen auf undefinierte Speicherbereiche bestehen !             *)
(*                                                                           *)
(* Alle Prozeduren pruefen, ob die Queue, die ihnen uebergeben wird, einen   *)
(* undefinierten Wert hat. ( --> defErr ).                                   *)
(*                                                                           *)
(* Wird ein beliebiger Fehler erkannt, wird dies ueber den Parameter <done>  *)
(* mitgeteilt; eine detailliertere Fehlermeldung erhaelt man ueber die Proze-*)
(* dur "LastQueueResult". Auf Wunsch kann auch mit "AssignQueueHandler" eine *)
(* automatische Fehlerbehandlung durch das Modul erfolgen.                   *)
(*                                                                           *)
(* Wegen der Pruefung auf undefinierte Queue muessen saemtliche Parameter    *)
(* vom Typ Queue als VAR-Parameter uebergeben werden, obwohl sie manchmal    *)
(* nur Eingangsparameter sind ( siehe Kommentar ).                           *)
(*___________________________________________________________________________*)
(*   24-Feb-90 , Holger Kleinschmidt                                         *)
(*****************************************************************************)


FROM  SYSTEM  IMPORT  (* TYPE *) ADDRESS, BYTE;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)

TYPE
      Queue;

      QueueResult  = ( queueOk, defErr, sizeErr, noMem, queueEmpty );

      QueueHandler = PROCEDURE ((* EIN  proc *) ARRAY OF CHAR,
                                (* EIN  qErr *) QueueResult   );

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)

  PROCEDURE  AssignQueueHandler ((* EIN/  -- *) handler : QueueHandler );

  PROCEDURE  UnAssignQueueHandler;

 (*-------------------------------------------------------------------------
  | Ist mit "AssignQueueHandler" eine Fehlerbehandlungsroutine definiert    |
  | worden, so wird diese jedesmal automatisch aufgerufen, wenn bei einer   |
  | Queueoperation ein Fehler aufgetreten ist; die Prozedur erhaelt als     |
  | Parameter den Fehler vom Typ "QueueResult" und den Namen der Prozedur,  |
  | in der der Fehler auftrat.                                              |
  | Nach Programmstart oder Aufruf von "UnAssignQueueHandler" wird vom Modul|
  | kein Handler beim Auftritt eines Fehlers aktiviert.                     |
  |                                                                         |
  | Beispiel fuer einen einfachen Handler:                                  |
  |                                                                         |
  | PROCEDURE Queuehandler( proc : ARRAY OF CHAR; fehler : QueueResult );   |
  |   BEGIN                                                                 |
  |     WriteLn;                                                            |
  |     WriteString('Fehler bei Queueoperation - ');                        |
  |     WriteString('Prozedur '); WriteString(proc); Write(':');            |
  |     WriteLn;                                                            |
  |     CASE  fehler  OF                                                    |
  |      | queueOk   : WriteString('Alles ok');                             |
  |      | defErr    : WriteString('Die benutzte Queue ist undefiniert!');  |
  |      | sizeErr   :                                                      |
  |          WriteString('Das Datenelement hat einen anderen Speicher');    |
  |          WriteString('bedarf,'); WriteLn;                               |
  |          WriteString('als bei der Queuedefinition angegeben.');         |
  |      | noMem     : WriteString('Kein freier Speicher mehr.');           |
  |      | queueEmpty: WriteString('Die Queue ist leer.');                  |
  |      ELSE                                                               |
  |        WriteString('Totaler Zusammenbruch...');                         |
  |     END; (* CASE *)                                                     |
  |     WriteLn; WriteLn;                                                   |
  |   END  Queuehandler;                                                    |
   -------------------------------------------------------------------------*)


   PROCEDURE  LastQueueResult ( ): QueueResult;

 (*-------------------------------------------------------------------------
  | Liefert das Resultat der letzten Queueoperation, falls <done> nicht aus-|
  | reichen sollte oder fuer die Prozeduren "Length" und "IsEmpty", die     |
  | keinen Erfolgsparameter <done> haben.                                   |
  |                                                                         |
  | Moegliche Kombinationen sind:                                           |
  |  - queueOk    : Es ist kein Fehler aufgetreten. Moegliches Ergebnis     |
  |                 aller Prozeduren.                                       |
  |  - queueEmpty : Es wurde versucht, ein Element aus einer leeren Queue   |
  |                 zu holen. Moegliches Ergebnis von "Remove" und "Look".  |
  |  - noMem      : der Speicher reicht nicht fuer die Ausfuehrung von      |
  |                 "Create" oder "Insert".                                 |
  |  - sizeErr    : Es wurde versucht, ein Element an die Queue anzuhaengen |
  |                 oder aus der Queue zu holen, das eine andere Speicher-  |
  |                 platzgroesse hat, als bei der Definition des Queue ange-|
  |                 geben wurde. Moegliches Ergebnis von "Insert", "Remove" |
  |                 und "Look".                                             |
  |  - defErr     : Es wurde versucht, eine Queueoperation mit einer unde-  |
  |                 finierten Queuevariable auszufuehren. Moegliches Resul- |
  |                 tat aller Prozeduren ausser "Create".                   |
   -------------------------------------------------------------------------*)

(*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*)


  PROCEDURE  Create ((* EIN/ -- *)     groesse : CARDINAL;
                     (* EIN/ -- *)     blkElem : CARDINAL;
                     (* -- /AUS *) VAR queue   : Queue;
                     (* -- /AUS *) VAR done    : BOOLEAN  );

 (*-------------------------------------------------------------------------
  | Richtet eine Queue und ihre Verwaltung ein. <groesse> ist die Groesse   |
  | der Elemente, die in <queue> abgelegt werden sollen. <blkElem> ist die  |
  | Anzahl der Elemente, fuer die jeweils ein neuer Speicherblock angefor-  |
  | dert wird. Ein grosser Wert fuer <blkElem> fuert zu geringerem Verwal-  |
  | tungsaufwand, vergroessert aber den Anteil des Speichers, der die meiste|
  | Zeit nicht genutzt wird.                                                |
  | <grosse> = 0, <blkElem> = 0 werden auf 1 korrigiert.                    |
  | Die Prozedur muss vor allen anderen Queueoperationen ausgefuehrt werden;|
  | <queue> ist nur fuer Elemente der angegebenen Groesse zu benutzen.      |
  | <queue> ist immer mindestens einen Speicherblock gross.                 |
  |                                                                         |
  | Moegliche Fehler: noMem                                                 |
   -------------------------------------------------------------------------*)


  PROCEDURE  Delete ((* EIN/AUS *) VAR queue : Queue;
                     (* -- /AUS *) VAR done  : BOOLEAN );

 (*-------------------------------------------------------------------------
  | Gegenstueck zu "Create": <queue> wird aus der Verwaltung entfernt, und  |
  | der belegte Speicherplatz freigegeben.                                  |
  | <queue> hat nach der Operation den Wert NIL.                            |
  |                                                                         |
  | Moegliche Fehler: defErr                                                |
   -------------------------------------------------------------------------*)


  PROCEDURE  IsEmpty ((* EIN/ -- *) VAR queue : Queue ): BOOLEAN;

 (*-------------------------------------------------------------------------
  | Testet, ob <queue> leer ist.                                            |
  |                                                                         |
  | Moegliche Fehler: defErr                                                |
   -------------------------------------------------------------------------*)

  PROCEDURE  Clear ((* EIN/AUS *) VAR queue : Queue;
                    (* -- /AUS *) VAR done  : BOOLEAN );

 (*-------------------------------------------------------------------------
  | Entfernt saemtliche Elemente aus <queue>, und gibt deren Speicherplatz  |
  | frei; <queue> selber bleibt erhalten.                                   |
  |                                                                         |
  | Moegliche Fehler: defErr                                                |
   -------------------------------------------------------------------------*)


  PROCEDURE  Length ((* EIN/ -- *) VAR queue : Queue ): CARDINAL;

 (*-------------------------------------------------------------------------
  | Liefert die Anzahl der Elemente in <queue>.                             |
  |                                                                         |
  | Moegliche Fehler: defErr                                                |
   -------------------------------------------------------------------------*)



  PROCEDURE  Insert ((* EIN/ -- *)     wert  : ARRAY OF BYTE;
                     (* EIN/AUS *) VAR queue : Queue;
                     (* -- /AUS *) VAR done  : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | <element> wird ans Ende von <queue> angefuegt.                          |
  |                                                                         |
  | Moegliche Fehler: defErr, sizeErr, noMem                                |
   -------------------------------------------------------------------------*)


  PROCEDURE  Remove ((* EIN/AUS *) VAR queue : Queue;
                     (* -- /AUS *) VAR wert  : ARRAY OF BYTE;
                     (* -- /AUS *) VAR done  : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Entfernt das erste Element von <queue>, und liefert es in <wert>.       |
  | Im Fehlerfall wird <wert> auf Null gesetzt.                             |
  |                                                                         |
  | Moegliche Fehler: defErr, sizeErr, queueEmpty                           |
   -------------------------------------------------------------------------*)


  PROCEDURE  Look ((* EIN/ -- *) VAR queue : Queue;
                   (* -- /AUS *) VAR wert  : ARRAY OF BYTE;
                   (* -- /AUS *) VAR done  : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Liefert das erste Element von <queue> in <wert>. <queue> wird nicht     |
  | veraendert. Im Fehlerfall wird <wert> auf Null gesetzt.                 |
  |                                                                         |
  | Moegliche Fehler: defErr, sizeErr, queueEmpty                           |
   -------------------------------------------------------------------------*)

END  Queues.
